package asm;

import org.objectweb.asm.*;
import org.objectweb.asm.commons.AdviceAdapter;

import static org.objectweb.asm.Opcodes.ASM7;

public class H_addTrycatch {

    public void addTrycatchByCoreAPI() throws Exception {
        ClassReader cr = Tool.getClassReader();
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
        ClassVisitor cv = new ClassVisitor(ASM7, cw) {


            @Override
            public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
                MethodVisitor mv = super.visitMethod(access, name, descriptor, signature, exceptions);

                if (!"test01".equals(name)) {
                    return mv;
                }
                // 开始的标签

                // 修改test01 进入方法
                return new AdviceAdapter(ASM7, mv, access, name, descriptor) {
                    Label startLabel = new Label();
                    Label endLable = new Label();

                    @Override
                    protected void onMethodEnter() {
                        super.onMethodEnter();
                        // mark start
                        mv.visitLabel(startLabel);
                        mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                        mv.visitLdcInsn("enter method");
                        mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

                    }

                    @Override
                    public void visitMaxs(int maxStack, int maxLocals) {
//                        // mark end
                        Label endLable = new Label();
//                        /**
//                         * startLabel 开始的标签
//                         * endLable 结束的标签
//                         * endLable 跳转的位置
//                         */
                        mv.visitTryCatchBlock(startLabel, endLable, endLable, null);
                        mv.visitLabel(endLable);
//                        // 打印异常
                        finallyBlock(Opcodes.ATHROW);
//                        // 抛出异常
                        mv.visitInsn(ATHROW);
                        super.visitMaxs(maxStack, maxLocals);

                    }

                    private void finallyBlock(int opcode) {
                        mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                        if (opcode == Opcodes.ATHROW) {
                            mv.visitLdcInsn("error exit method");
                        } else {
                            mv.visitLdcInsn("normal exit method");
                        }

                        mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);

                    }

                    // 退出方法
                    @Override
                    protected void onMethodExit(int opcode) {
                        super.onMethodExit(opcode);

                        finallyBlock(opcode);
                    }
                };
            }

        };
        //cr.accept(cv,ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG);
        cr.accept(cv, 0);
        byte[] bytesModifield = cw.toByteArray();

        Tool.save(this.getClass(), Application.class, bytesModifield);

    }


    public static void main(String[] args) throws Exception {
        H_addTrycatch tc = new H_addTrycatch();
        // 修改方法
        tc.addTrycatchByCoreAPI();
        // 调用类
        new Application().test01();
    }
}
